import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: ZhongJinTao
 * Date: 2024-03-14
 * Time: 8:34
 */
public class TcpEchoServer {
    ServerSocket socket = null;

    public TcpEchoServer(int serverPort) throws IOException {
        socket = new ServerSocket(serverPort);
    }

    public void start() throws IOException {
        System.out.println("服务器启动");
//        ExecutorService pool = Executors.newCachedThreadPool();
        while (true) {
            //通过 accept 这个方法来 “接听电话”，然后才能通信
            Socket clientSocket = socket.accept();
            Thread t = new Thread(() -> {
                //通过这个方法来处理一次连接，连接的过程会涉及到多次请求响应交互
                processConnection(clientSocket);
            });
            t.start();
//            pool.submit(new Runnable() {
//                @Override
//                public void run() {
//                    processConnection(clientSocket);
//                }
//            });
        }
    }
    //通过这个方法来处理一次连接，连接的过程会涉及到多次请求响应交互
    private void processConnection(Socket clientSocket) {
        System.out.printf("[%s : %d] 客户端上线\n", clientSocket.getInetAddress(), clientSocket.getPort());
        //循环读取客户端请求并返回响应
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()) {
            while (true) {
                Scanner scanner = new Scanner(inputStream);
                if(!scanner.hasNext()) {
                    //读取完毕，客户端断开连接，就会产生读取完毕
                    System.out.printf("[%s : %d] 客户端下线\n", clientSocket.getInetAddress(), clientSocket.getPort());
                    break;
                }
                //1、接受从客户端发来的请求,解析请求（将请求转换为字符串）为了方便，直接使用Scanner读取
                //  读取请求并解析. 这里注意隐藏的约定. next 读的时候要读到空白符才会结束.
                //    因此就要求客户端发来的请求必须带有空白符结尾. 比如 \n 或者空格.
                //客户端发来的请求要包含 “\n”
                String request = scanner.next();
                //2、计算请求
                String response = process(request);
                //3、把计算的响应返回给客户端
                //也可以通过下面的这种方式写回，但下面这种方式不好添加 "\n"
                //outputStream.write(response.getBytes(), 0, response.getBytes().length);
                // 也可以给outputStream套上一层，可以更方便的加上 "\n"
                PrintWriter writer = new PrintWriter(outputStream);
                writer.println(response);
                //刷新缓冲器
                writer.flush();
                //打印日志
                System.out.printf("[%s : %d] res: %s resp: %s\n", clientSocket.getInetAddress(),
                        clientSocket.getPort(), request, response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                clientSocket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);
        tcpEchoServer.start();
    }
}
